import time
import requests
import numpy as np
import pytest
from math import exp

# ---------- 配置（请根据实际修改） ----------
BASE_URL = "http://127.0.0.1:8000"
UPLOAD_URL = f"{BASE_URL}/ecg_upload"

# MySQL 配置（请改成你的）
DB_HOST = "localhost"
DB_PORT = 3306
DB_USER = "root"
DB_PASS = "202267"
DB_NAME = "ecg_platform"

# 测试设备 / 用户（确保在 DB 中存在）
DEVICE_ID = "ECG2025000100"
TEST_USER = "user100"

# 采样配置
FS = 250   # 250 Hz
UPLOAD_SLEEP = 2  # 上传后等待 DB 写入的秒数（可按需调大）
DURATION_SEC = 8  # 测试用较短时长以加快测试

# ---------- DB helper ----------
def db_connect():
    return pymysql.connect(host=DB_HOST, port=DB_PORT, user=DB_USER,
                           password=DB_PASS, database=DB_NAME, charset="utf8mb4",
                           cursorclass=pymysql.cursors.DictCursor, autocommit=True)

def count_alerts_for_device(device_id):
    conn = db_connect()
    try:
        with conn.cursor() as c:
            c.execute("SELECT COUNT(*) AS cnt FROM alerts WHERE device_id=%s", (device_id,))
            return c.fetchone()["cnt"]
    finally:
        conn.close()

def get_latest_ecg_record(device_id):
    conn = db_connect()
    try:
        with conn.cursor() as c:
            c.execute("SELECT * FROM ecg_records WHERE device_id=%s ORDER BY id DESC LIMIT 1", (device_id,))
            return c.fetchone()
    finally:
        conn.close()

def count_ecg_records(device_id):
    conn = db_connect()
    try:
        with conn.cursor() as c:
            c.execute("SELECT COUNT(*) AS cnt FROM ecg_records WHERE device_id=%s", (device_id,))
            return c.fetchone()["cnt"]
    finally:
        conn.close()

def shift_latest_record_start_time(device_id, minutes):
    """将最新记录的 start_time 和 end_time 同时往前移动 N 分钟"""
    conn = pymysql.connect(host="localhost", user="root", password="202267", database="ecg_platform")
    try:
        with conn.cursor() as c:
            c.execute("""
                UPDATE ecg_records
                SET start_time = DATE_SUB(NOW(), INTERVAL %s MINUTE),
                    end_time = DATE_SUB(NOW(), INTERVAL %s MINUTE)
                WHERE id = (
                    SELECT id FROM (
                        SELECT id FROM ecg_records
                        WHERE device_id=%s
                        ORDER BY id DESC
                        LIMIT 1
                    ) t
                )
            """, (minutes, minutes, device_id))
        conn.commit()
    finally:
        conn.close()

# ---------- 信号生成 ----------
def ecg_waveform(t):
    """简化的 PQRST 波形（单拍）"""
    p = 0.15 * exp(-((t - 0.1) ** 2) / (2 * 0.015 ** 2))
    q = -0.25 * exp(-((t - 0.18) ** 2) / (2 * 0.010 ** 2))
    r = 1.2 * exp(-((t - 0.20) ** 2) / (2 * 0.012 ** 2))
    s = -0.35 * exp(-((t - 0.25) ** 2) / (2 * 0.015 ** 2))
    t_wave = 0.3 * exp(-((t - 0.35) ** 2) / (2 * 0.04 ** 2))
    return p + q + r + s + t_wave

def generate_normal_sinus(duration_sec=8, hr=75):
    period = 60.0 / hr
    samples_per_beat = max(1, int(period * FS))
    beats = max(1, int(duration_sec / period))
    data, timestamps = [], []
    start = time.time()
    for b in range(beats):
        for i in range(samples_per_beat):
            val = ecg_waveform(i / FS) + np.random.uniform(-0.02, 0.02)
            data.append(round(float(val), 3))
            timestamps.append(round(start + i / FS, 3))
        start += period
    return data, timestamps

# ---------- HTTP 上传 ----------
def upload_batch(device_id, data_list, timestamps_list):
    data_str = ",".join(map(lambda x: f"{x:.3f}", data_list))
    ts_str = ",".join(map(lambda x: f"{x:.3f}", timestamps_list))
    res = requests.post(UPLOAD_URL, data={
        "device_id": device_id,
        "data": data_str,
        "timestamps": ts_str
    }, timeout=10)
    return res

# ---------- 测试用例 ----------
@pytest.mark.order(1)
def test_t02_upload_abnormal_rhythm_triggers_alert():
    # 先记录报警数
    before = count_alerts_for_device(DEVICE_ID)

    # 构造非窦性心律：频率明显不稳定 + 噪声
    t = np.arange(0, 5, 1/FS)
    freqs = 1.0 + 0.6 * np.sin(0.8 * np.pi * t)  # 频率随时间波动
    signal = 0.7 * np.sin(2 * np.pi * freqs * t) + 0.4 * np.random.randn(len(t))
    data = list(map(float, signal))
    timestamps = [time.time() + i/FS for i in range(len(data))]

    res = upload_batch(DEVICE_ID, data, timestamps)
    assert res.status_code == 200, f"上传失败: {res.text}"

    time.sleep(UPLOAD_SLEEP)
    after = count_alerts_for_device(DEVICE_ID)
    assert after > before, f"❌ 非窦性心律应触发报警 (before={before}, after={after})"

@pytest.mark.order(2)
def test_t03_upload_flat_signal_triggers_alert():
    before = count_alerts_for_device(DEVICE_ID)

    data = [0.01] * (FS * 3)   # 3 秒平线近似
    timestamps = [time.time() + i/FS for i in range(len(data))]

    res = upload_batch(DEVICE_ID, data, timestamps)
    assert res.status_code == 200, f"上传失败: {res.text}"

    time.sleep(UPLOAD_SLEEP)
    after = count_alerts_for_device(DEVICE_ID)
    assert after > before, f"❌ 平线信号应触发报警 (before={before}, after={after})"

@pytest.mark.order(3)
def test_t04_upload_sine_signal_triggers_alert():
    before = count_alerts_for_device(DEVICE_ID)

    t = np.arange(0, 5, 1/FS)
    sig = 1.0 * np.sin(2 * np.pi * 2 * t)  # 2Hz 正弦
    data = list(map(float, sig))
    timestamps = [time.time() + i/FS for i in range(len(data))]

    res = upload_batch(DEVICE_ID, data, timestamps)
    assert res.status_code == 200, f"上传失败: {res.text}"

    time.sleep(UPLOAD_SLEEP)
    after = count_alerts_for_device(DEVICE_ID)
    assert after > before, f"❌ 正弦波信号应触发报警 (before={before}, after={after})"

import pymysql

def shift_latest_record_start_time(device_id, minutes):
    """将设备的最新心电记录 start_time 往前移动 N 分钟"""
    conn = pymysql.connect(host="localhost", user="root", password="202267", database="ecg_platform")
    try:
        with conn.cursor() as c:
            c.execute("""
                UPDATE ecg_records
                SET start_time = DATE_SUB(NOW(), INTERVAL %s MINUTE)
                WHERE id = (
                    SELECT id FROM (
                        SELECT id FROM ecg_records
                        WHERE device_id=%s
                        ORDER BY id DESC
                        LIMIT 1
                    ) t
                )
            """, (minutes, device_id))
        conn.commit()
    finally:
        conn.close()

@pytest.mark.order(4)
def test_t05_upload_record_split_after_10min():
    """
    ✅ 模拟10分钟后自动新建心电记录（方案A1：调整数据库时间）
    """
    before_records = count_ecg_records(DEVICE_ID)

    # 上传一段正常数据
    data1 = [0.1] * (FS * 2)
    ts1 = [time.time() + i/FS for i in range(len(data1))]
    r1 = upload_batch(DEVICE_ID, data1, ts1)
    assert r1.status_code == 200, f"第一次上传失败: {r1.text}"

    # ✅ 模拟：把最后一条记录的 start_time 往前推11分钟
    shift_latest_record_start_time(DEVICE_ID, 11)

    # 上传第二段数据
    data2 = [0.2] * (FS * 2)
    ts2 = [t + 600 for t in ts1]  # 时间戳也偏移600秒，更真实
    r2 = upload_batch(DEVICE_ID, data2, ts2)
    assert r2.status_code == 200, f"第二次上传失败: {r2.text}"

    after_records = count_ecg_records(DEVICE_ID)
    print(f"📊 before={before_records}, after={after_records}")
    assert after_records > before_records, f"❌ 未新建记录: before={before_records}, after={after_records}"
    print("✅ 超过10分钟自动新建记录成功")
